//
// GPSMapEdit
// (c) Konstantin Galichsky (kg@geopainting.com), 2002-2007
//
// Degree grid drawing.
//

# include "StdAfx.h"
# include "Grid.h"
# include "Map.h"
# include "Scale.h"
# include "Position.h"
# include "fast_floor.h"
# include "DrawHelpers.h"
# include "Globals.h"

static
double GetBestGrid (double _fMinGrid) {
	static const double fStdGrids [] = {180., 90., 60., 45., 20., 10., 5., 2., 1., 1/2., 1/3., 1/6., 1/12., 1/30., 1/60.};

	if (_fMinGrid > fStdGrids [0])
		return fStdGrids [0];
	else 
		for (size_t c = 1; c < sizeof (fStdGrids)/sizeof (fStdGrids [0]); ++ c) {
			if (_fMinGrid > fStdGrids [c])
				return fStdGrids [c - 1];
		}

	return fStdGrids [sizeof (fStdGrids)/sizeof (fStdGrids [0]) - 1];
}

static
void GetDegMin (float _f, float _fStep, char * _strText) {
	const float fAbs = _f > 0 ? _f : - _f;
	const int deg = fast_floor (fAbs + 1/120.f);

	if (_fStep >= 1)
		::sprintf (_strText, "%d%s", deg, g_strDegreeSign);
	else {
		const int min = fast_floor ((fAbs - deg)*60 + .5f);
		::sprintf (_strText, "%d%s %02d'", deg, g_strDegreeSign, min);
	}
}

void ShowGrid (HDC _hDC, const RECT & _rect) {
	{
		CCritSec::CLock lock (g_cs);
		if (g_map.rectBound.Invalid ())
			return;
	}

	rect_t rectVisible;
	GetVisibleRect (rectVisible);

	::SelectObject (_hDC, g_hpenGrid);
	::SetROP2 (_hDC, R2_COPYPEN);
	::SelectObject (_hDC, g_hFont);
	::SetTextAlign (_hDC, TA_LEFT | TA_TOP);

	//
	// Vertical grid.
	//

	const size_t cMinXGridInPixels = g_lWidth/2 < 100 ? g_lWidth/2 : 100;
	const double fMinXGrid = cMinXGridInPixels/g_kX;
	const double fXGrid = GetBestGrid (fMinXGrid);

	const double fMinX = __max (-360,  ::ceil (rectVisible.x0/fXGrid - .5f)*fXGrid);
	const double fMaxX = __min (360, fast_floor (rectVisible.x1/fXGrid + .5f)*fXGrid + 1e-6f);

	for (double fX = fMinX; fX <= fMaxX; fX += fXGrid) {
		const long lX = XToScreen (fX);
		if (lX < 0 || lX >= g_lWidth)
			continue;

		::MoveToEx (_hDC, lX, 0, NULL);
		::LineTo (_hDC, lX, g_lHeight);

		char strText [64];
		GetDegMin (fX, fXGrid, strText);

		DrawText2 (_hDC, lX + 2, 2, strText, c_colGray);
	}

	//
	// Horizontal grid.
	//

	const size_t cMinYGridInPixels = g_lHeight/2 < 100 ? g_lHeight/2 : 100;
	const double fMinYGrid = cMinYGridInPixels/g_kY;
	const double fYGrid = GetBestGrid (fMinYGrid);

	const double fMinY = __max (-360, ::ceil (rectVisible.y0/fYGrid - .5f)*fYGrid);
	const double fMaxY = __min (360,  fast_floor (rectVisible.y1/fYGrid + .5f)*fYGrid + 1e-6f);

	for (double fY = fMinY; fY <= fMaxY; fY += fYGrid) {
		const long lY = YToScreen (fY);
		if (lY < 0 || lY >= g_lHeight)
			continue;

		::MoveToEx (_hDC, 0, lY, NULL);
		::LineTo (_hDC, g_lWidth, lY);

		char strText [64];
		GetDegMin (fY, fYGrid, strText);

		DrawText2 (_hDC, 2, lY + 2, strText, c_colGray);
	}
}
